La Regenta
Análisis de la novela en R

Introducción

En este apartado, se analiza la obra “La Regenta” de Leopoldo Alas Clarín a partir de diferentes técnicas de análisis de contenido. Se tratan, en su mayor parte, de acercamientos estadísticos o cuantitativos a los textos literarios. Por lo tanto, representan una visión limitada de la obra y solo complementaria a la lectura y el análisis cualitativo detenido de la misma.

Nos acercaremos al texto, primero, intentando descubrir cuáles palabras se destacan, sus frecuencias y distribuciones. Luego, analizaremos la obra desde la perspectiva de los personajes, sus relaciones y sus apariciones en la obra.

Las palabras que cuentan

El primer paso del análisis consiste en cargar los datos que hemos preparado en la sección de preparación de los datos y convertirlo en un objeto de tipo corpus. Para ello, emplearemos el paquete de R llamado quanteda, que resulta bastante completo para el análisis de contenido.

El código abajo carga los datos en la memoria, los convierte en un corpus y muestra algunas estadísticas básicas de los capítulos de la obra, como el número de palabras (tokens), el número de palabras únicas (types) y la cantidad de frases.

Code
# carga los datos de "La Regenta"
load("../textos/Regenta.RData")

# carga el paquete quanteda para 
# algunos análisis
library(quanteda)

# carga el paquete reactable que
# permitirá mostrar los resultados en
# una tabla interactiva
library(reactable)

# Elimina el título y el prólogo
regc <- regc[3:nrow(regc),]

# convierte en un documento corpus
cp <- corpus(regc, text_field = "texto")

# define los capítulos como nombre
# de los documentos
docnames(cp) <- regc$capitulo

# muestra estadísticas básicas de
# cada capítulo
reactable(summary(cp))


Vemos que los treinta capítulos de la obra tienen una extensión que va de poco más de ocho mil hasta aproximadamente veintiún mil palabras. No resulta nada sorprendente que las palabras únicas y el número de frases varíen de forma proporcional.

Frecuencias de palabras

El próximo paso consiste en convertir el corpus en una matriz de términos. Para ello, primero convertimos los textos en tokens, que son las palabras individuales de los textos. Luego, eliminamos las palabras vacías (stopwords) y las palabras que no aportan información, como los números y los signos de puntuación. Este objeto será luego empleado en diversas técnicas de análisis de contenido.

Code
# convierte en tokens y remueve
# punctuación, símbolos y números
tk <- tokens(cp, remove_punct = TRUE, 
                  remove_numbers = TRUE, 
                  remove_symbols = TRUE)

# Elimina las palabras vacías
tk <- tokens_remove(tk, stopwords("es"))


Para poder explorar cuáles palabras se destacan en la obra podemos emplear una técnica llamada análisis de frecuencia de palabras. En este caso, crearemos una matriz de términos de documentos (document-feature matrix), que es una representación matricial de los textos en la que las filas representan los documentos y las columnas las palabras. Cada celda de la matriz contiene el número de veces que una palabra aparece en un documento.

El código abajo crea la matriz y convierte todos los términos en minúsculas para facilitar el cuenteo. Luego, muestra las cincuenta palabras más frecuentes en la obra.

Code
# convierte en una matriz de términos
dtm <- dfm(tk, 
           tolower = TRUE)

# muestra las 50 palabras más frecuentes
topfeatures(dtm, 50)
      don        si       ana     usted magistral   aquella     aquel    álvaro 
     1789      1164       894       822       767       758       731       488 
   víctor      casa   regenta     señor   vetusta      allí       ser   después 
      487       477       467       458       455       446       430       415 
    decía      doña       vez     mesía     podía     ahora      bien      ojos 
      414       411       390       372       368       361       349       346 
   fermín       así       iba       dos    quería      dijo   siempre     menos 
      345       344       333       330       328       325       325       322 
    mismo    hombre       tan      vida      dios     veces quintanar     mundo 
      318       314       312       311       309       305       303       285 
    mujer     todas     sabía       ver    tiempo      alma       día   parecía 
      284       279       279       279       278       275       271       267 
     amor   aquello 
      267       265 


En este caso, hemos considerado palabras aisladas, pero podemos repetir el análisis con bigramas o trigramas, que son secuencias de dos o tres palabras consecutivas. Estas combinaciones permiten encontrar secuencias de ideas que pueden revelar ciertos contenidos o patrones en el texto.

Code
bi <- tokens_ngrams(tk, n = 2)

# convierte en una matriz de términos
dtm <- dfm(bi)

# muestra los 50 bigramas más frecuentes
topfeatures(dtm, 50)
     don_víctor      don_álvaro      don_fermín     don_pompeyo      doña_paula 
            450             390             302             123             119 
        tal_vez      don_santos  doña_petronila      don_carlos   aquella_noche 
            105              93              66              60              51 
  aquel_momento    don_custodio        doña_ana    doña_anuncia        cada_vez 
             48              47              47              47              46 
   don_cayetano   aquella_tarde      don_frutos     doña_camila señor_magistral 
             46              45              43              38              37 
   aquel_hombre   don_saturnino        dos_tres  don_robustiano     don_saturno 
             36              35              34              34              32 
    pocas_veces    todas_partes    muchas_veces     usted_señor        cada_día 
             32              31              31              31              30 
  aquella_mujer        si_usted       aquel_día       podía_ser        don_juan 
             30              30              29              29              29 
       voz_baja       debía_ser     doña_rufina       buen_mozo      ana_ozores 
             28              28              28              27              26 
  día_siguiente    álvaro_mesía  caserón_ozores      aire_libre      mire_usted 
             26              26              26              25              25 
   santa_teresa    mundo_entero  cualquier_cosa     doña_águeda       señor_don 
             25              24              24              24              23 
Code
tri <- tokens_ngrams(tk, n = 3)

# convierte en una matriz de términos
dtm <- dfm(tri)

# muestra los 50 trigramas más frecuentes
topfeatures(dtm, 50)
         don_álvaro_mesía      don_pompeyo_guimarán      don_víctor_quintanar 
                       22                        20                        17 
   don_saturnino_bermúdez       don_santos_barinaga        don_frutos_redondo 
                       16                        13                        11 
      casa_doña_petronila            dos_tres_veces          dio_media_vuelta 
                       11                         9                         9 
          doña_ana_ozores             si_don_víctor                  ta_ta_ta 
                        8                         8                         8 
          casa_don_víctor         darse_cuenta_ello             don_álvaro_si 
                        8                         8                         8 
 doña_petronila_rianzares            don_fermín_pas      jefe_partido_liberal 
                        8                         7                         7 
partido_liberal_dinástico          don_tomás_crespo        almunia_don_godino 
                        7                         7                         7 
       hermano_mayor_alma            _la_cruz_roja_     don_robustiano_somoza 
                        7                         7                         7 
                 ja_ja_ja        media_hora_después            fray_luis_león 
                        7                         7                         6 
         don_juan_tenorio          decía_don_álvaro            dio_paso_atrás 
                        6                         6                         6 
           ana_don_álvaro           dijo_don_víctor             si_don_álvaro 
                        6                         6                         6 
 don_custodio_beneficiado          señor_don_fermín          gritó_don_víctor 
                        5                         5                         5 
        daba_media_vuelta    hago_cuestión_personal          aquel_don_álvaro 
                        5                         5                         5 
         usted_señor_foja             dijo_voz_baja            don_víctor_vio 
                        5                         5                         5 
         pobre_don_santos        treinta_cinco_años  beneficiado_don_custodio 
                        5                         4                         4 
        hablaban_voz_baja   visitación_olías_cuervo     don_restituto_mourelo 
                        4                         4                         4 
         primera_vez_vida          señor_don_víctor 
                        4                         4 


¿Qué vemos en los resultados de los bigramas y trigramas? El primer patrón que emerge es la presencia de nombres de personajes, como “don Víctor Quintanar”, “don Álvaro” o “do Fermín”. También aparecen nombres de lugares, como “Vetusta” o “Santa Cruz”. Por último, encontramos algunas secuencias que parecen describir acciones o situaciones, como “señor marqués” o “señor don Fermín”.

Colocaciones

Otro recurso útil a la hora de explorar los términos más frecuentes en un texto proviene de las colocaciones. Las colocaciones son secuencias de palabras que aparecen juntas con más frecuencia de lo que se esperaría por azar. En otras palabras, son secuencias de palabras que tienen un significado especial o que se emplean en un contexto específico.

El código abajo emplea la función textstat_collocations del paquete quanteda.textstats para encontrar las colocaciones más frecuentes en el texto1. En este caso, hemos considerado solo las colocaciones que aparecen al menos diez veces en el texto.

Code
# Carga el paquete
library(quanteda.textstats)

# Encuentra las colocaciones
col <- textstat_collocations(tk, 
                             min_count = 10)

# Muestra los resultados
reactable(col, resizable = TRUE, wrap=F)


Como hemos podido ver, vuelven a aparecer los nombres de los personajes, lugares, pero ahora también llaman la atención algunos términos que indican frecuencia (algunas veces, muchas veces, dos tres, cada día) o hacen referencia al tiempo (aquel momento, aquella tarde, media hora). Estos términos pueden ser útiles para entender el contexto en el que se desarrolla la obra.

Palabras-clave

Otro recurso que disponemos para examinar el contenido de un texto es el análisis de palabras-clave. Podemos interesarnos por un tema o concepto específico y buscar en qué contexto aparece en el texto. En este caso, vamos a buscar la palabra “adulterio” y ver en qué contexto aparece en la obra.

Una estrategia sería ver cuántas veces aparece “adulterio” en la novela, pero eso no nos daría mucha información sobre el contexto en el que se emplea. Por eso, vamos a emplear la función kwic (keyword in context) del paquete quanteda para buscar la palabra en el texto y ver en qué contexto aparece.

El resultado es una tabla que muestra la palabra “adulterio” y las palabras que la rodean en el texto. De esta manera, podemos entender mejor cómo se emplea la palabra en la obra y qué significado tiene en el contexto de la novela.

Code
# Carga el paquete
library(quanteda)

# recreamos los tokens
# sin remover la puntuación
# o los stopwords
tk <- tokens(cp)

# Busca la palabra "adulterio" en
# su contexto
kw_amor <- kwic(tk, 
                pattern =  "adulterio")

# Muestra los resultados
reactable(kw_amor, 
          resizable = TRUE, 
          wrap=F)


Saltan a la vista los calificativos y acciones que se revelan cuando se analiza el contexto de “adulterio”. Se ven atributos como “repugnante”, “infame”, “ominoso”, “escándalo”. También acciones que se asocian como respuesta al adulterio: “vengar”, “duelo”, “batirme”. En pocas palabras, se nota el rechazo social al adulterio y se puede fácilmente imaginar un desaforado cornudo, pistola en mano, buscando venganza.

Podemos emplear un tipo de visualización de datos llamado árbol de palabras para representar gráficamente el contexto en el que aparece la palabra “adulterio”. En este caso, vamos a emplear la función wordtree del paquete tenet para crear un árbol de palabras que muestre las palabras que aparecen antes y después de “adulterio” en el texto. No obstante, como hemos visto, la palabra “adulterio” no aparece muchas veces en la novela, por lo que el árbol de palabras no será muy complejo ni tampoco interesante. Probemos algo más picante, que salga el “amor”.

Code
library(tenet)


wordtree(cp, "amor")


Ahora las cosas se ponen más interesantes. Vemos que las palabras cambian de tamaño según su frecuencia, de modo que sabemos que “amor de” resulta más común que “amor del”, por ejemplo.

Pero, ¿qué palabras debo elegir? ¿Cómo sé cuáles son las más relevantes? Para responder a estas preguntas, podemos emplear una técnica llamada keyness. Esta técnica compara la frecuencia de una palabra en un texto con su frecuencia en otro texto de referencia. Si la palabra aparece poco en el texto de referencia, entonces debería aparecer poco en el texto elegido. Si no es así, tenemos una palabra clave, entendida como un término cuya frecuencia resulta muy superior a la esperada.

El capítulo 8 de la novela es una delicia para emplear esa técnica. Se trata de un pasaje que contiene la descripción de una merienda en la casa de la marquesa de Vegallana y sus “preparativos” en la cocina. Emplearemos la función textstat_keyness del paquete quanteda.textstats para encontrar las palabras clave.

Code
# Cargamos los paquetes necesarios
library(quanteda.textstats)
library(quanteda.textplots)

# Volvemos a crear los tokens
# sin puntos ni stopwords

# convierte en tokens y remueve
# punctuación, símbolos y números
tk <- tokens(cp, remove_punct = TRUE, 
                  remove_numbers = TRUE, 
                  remove_symbols = TRUE)

# Elimina las palabras vacías
tk <- tokens_remove(tk, stopwords("es"))

# Creamos la matriz de frecuencia
# de términos
dtm <- dfm(tk)

# Calculamos la estadística, 
# considerando el capítulo 8 como
# objetivo y el resto de la novela
# como referencia
key <- textstat_keyness(dtm, 
                        target = "08")

# Visualizamos los resultados
textplot_keyness(key)


Las palabras asociadas a la comida se destacan: cocina, despensa, cocinero, fogón, pinche, merienda, almíbares. También se destacan palabras asociadas a la nobleza: marques, marquesa, regencia, así como el lugar de las tertulias (el salón amarillo). De otro lado, vemos las palabras que está fuera: Magistral, Fermín, Víctor, Ana, Quintanar, que son personajes que no aparecen en el capítulo 8 o apenas lo hacen.

Podemos añadir información empleando la función plotKeyness del paquete tenet para visualizar los resultados de una manera interactiva y bidimensional. Nos interesa saber, además del chi2, la frecuencia de las palabras. No es lo mismo una palabra rara que aparece poco que otra que no resulta tan común en la obra, pero que se emplea mucho en el capítulo en cuestión.

Code
# carga el paquete
library(tenet)

# crea el gráfico
plotKeyness(cp, 
            ref.cat= "08")


De ese modo, las palabras que se encuentren lo más lejos del eje horizontal y vertical serán las más específicas del capítulo. Por otra parte, aquellas que se encuentren más a la derecha, so. las más frecuentes en el capítulo 8. Por lo tanto, términos como “visita”, “cocina”, “marqués” se destacan tanto por su particular incidencia en el capítulo, como por su alta frecuencia. También vemos en rojo las palabras empleadas menos que lo esperado.

Si queremos analizar cuáles son las expresiones de peso en los demás capítulos, basta cambiar el argumento ref.cat por el número del capítulo que nos interese. Estos pasos exploratorios nos permiten tener una idea de los temas y personajes que aparecen en cada capítulo y, por consiguiente, de las palabras clave que los caracterizan.

Codificación temática

Entendemos por codificación temática el proceso de análisis de un texto con el propósito de identificar ideas, conceptos y temas recurrentes. Se utiliza de forma amplia en las ciencias sociales, como la sociología o la antropología, para analizar entrevistas, encuestas o documentos. En este caso, vamos a emplear la codificación temática para identificar los temas y conceptos que aparecen en la novela.

Como temas, por ejemplo, podemos tener el tiempo (las estaciones del año, el paso del tiempo, el momento del día, las fiestas religiosas), el espacio (el hogar, los ambientes de interacción social, la iglesia), la familia (los padres, los hijos, los hermanos), la sociedad (los nobles, los plebeyos, los campesinos), entre otros.

La forma más tradicional de codificación temática consiste en imprimir los documentos, leerlos detenidamente y realizar marcas o anotaciones en los márgenes. Sin embargo, en la era digital, podemos emplear herramientas de análisis de texto que nos ayudan a llevar a cabo esta tarea de forma más rápida y eficiente. Los diccionarios (o léxicos) son una de las más comunes.

El uso de diccionarios

Un diccionario corresponde a un conjunto de palabras clave asociados a un tema. Por ejemplo, cuando pienso en la familia, me vienen a la mente palabras como “padre”, “madre”, “hijo”, “hermano”, “hermana”,“tío”, “tía”, “abuelo”, “abuela”. Algunos más radicales incluirían los cuñados y parientes más lejanos. Si lo expresara de forma algorítmica sería algo así:

familia = c(“padre”, “madre”, “hijo”, “hermano”, “hermana”, “tío”, “tía”, “abuelo”, “abuela”)

Al buscar esas palabras en uno o varios textos, sabré que se menciona de alguna manera la familia y, principalmente, dónde y cuántas veces.

Abajo hemos creado un diccionario con palabras clave asociadas a diferentes temas. En este caso, hemos considerado la familia, la sociedad, la iglesia, la economía, los sentimientos, el misticismo, el adulterio, el espacio y el tiempo.

Luego, utilizo la función tagCorpus del paquete tenet para etiquetar de forma automática los textos con las palabras clave del diccionario frase a frase. Este procedimiento también me dice cuál es la categoría o tema más importante encontrado en la frase, cuáles son todos los temas encontrados, la cantidad de categorías y el número de palabras clave coincidentes. También permite filtrar y reordenar los resultados.

Code
# Crea un diccionario con palabras clave
# sobre algunos temas de interés en la
# novela
dic <- dictionary(
  list(
    familia=c("padre", "madre", "hijo", "hija", 
              "hermano", "hermana"),
    sociedad=c("vetustense","puebl","ciudad","conversa",
               "amig","noble","arist"),
    iglesia=c("cura","obispo","sacerdo","confesión",
              "religión","religios","canónig","capilla"),
    economia=c("dinero","deuda","negoci","trabaj",
               "fortuna","\\brico","\\brica"),
    sentimientos=c("culpa","alegr","\\bamor\\b","remordimiento",
                   "ridículo","vergüenza","triste"),
    misticismo=c("Fermín de Pas","Fermín","\\bde Pas\\b",
                 "magistral", "espirit","dios"),
    adulterio=c("Álvaro","Mesía","adulte","amante",
                "Presidente del", "marido", 
                "placer", "pasión", "amante","amorío"),
    espacio=c("casino","catedral","vivero","\\bcasa\\b",
              "espolón","teatro"),
    tiempo=c("otoño","verano","invierno","primavera",
             "semana santa","navidad","\\bdía\\b","noche",
             "tarde","la mañana","madrugada")
  )
)
    
# Carga el paquete tenet
library(tenet)

# Genera el etiquetado de 
# las frases según el diccionario
tagCorpus(cp, 
          dic, 
          reshape.to = "sentence", 
          defaultPageSize = 3)


El resultado son frases palabras pintadas de distintos colores de acuerdo con los temas a que pertenecen, como si hubiesen sido resaltadas con un marcador. De ese modo, se pude realizar una lectura rápida y visual de la incidencia de los temas en el texto, manteniendo todo el contexto de la obra.

Ubicación de temas en el texto

La tabla anterior resulta muy útil si queremos examinar las palabras en su contexto y regresar al documento para entender mejor cómo se utilizan. Sin embargo, si queremos tener una visión general de la distribución de los temas en el texto, podemos utilizar un gráfico de dispersión léxica. Se trata de una técnica de visualización de datos que representa un texto como un intervalor cortado por puntos o líneas verticales que corresponden a las palabras clave encontradas.

La función plotLexDiv del paquete tenet permite generar un gráfico de dispersión léxica que muestra la distribución de las palabras clave en el texto coloreadas por tema del diccionario. No se recomienda utilizar muchas categorías en un solo gráfico, puesto que la visualización se vuelve confusa y resulta muy difícil identificar patrones.

El siguiente código genera un gráfico de dispersión léxica, utilizando un diccionario con palabras clave asociadas a los temas de espacio y tiempo.

Code
# Crea un diccionario solo
# con dos temas: espacio y tiempo
dicf <- dictionary(
  list(
    espacio=c("casino","catedral","vivero",
              "casa","espolón","teatro",
              "calle","plaza","Paseo de Verano",
              "salón","tertulia"),
    tiempo=c("otoño","verano","invierno","primavera",
             "semana santa","navidad","\\bdía\\b","noche",
             "tarde","la mañana","madrugada")
))

# Crea el gráfico de dispersión
# léxica
plotLexDiv(cp, 
           dicf, 
           title ='La Regenta', 
           subtitle = "Espacio y tiempo en la novela", 
           palette = pal$cat.brewer.Dark2.8[c(1:4)])


Como podemos observar, las palabras clave relacionadas al espacio y tiempo se intercalan sin presentar un patrón claro. Por ello, sería útil realizar un análisis más detallado de los espacios (y de los tiempos) mencionados en la novela. Para ello, podemos utilizar la función filterWords del paquete tenet para seleccionar solo las palabras clave relacionadas al espacio y generar un gráfico de dispersión léxica interactivo que muestre la distribución de estos términos en el texto empleando la función plotSpike.

Creamos un nuevo diccionario con tres categorías analíticas del espacio: social, religioso y doméstico. El primer tipo reúne aquellos lugares de encuentro y diversión, como casinos, teatros y salones donde se da la interacción de los personajes nobles y de alta sociedad.

El segundo se encuentra representado por los lugares de culto, como catedrales y capillas. Son parte de los dominios de Fermín de Pas y su importancia en la trama viene de la fe que confesa Ana y su relación con el misticismo.

El tercero congrega el ambiente doméstico de carácter íntimo. Son lugares de vida cotidiana, como la casa, las habitaciones, la alcoba y las cocinas. Muchas de las escenas de la novela transcurren en estos espacios, donde se reflejan las angustias de Ana, como la expresión y transgresión de la intimidad del hogar.

Code
# Crea un diccionario solo sobre espacio,
# con subcategorías más detalladas
dicf <- dictionary(
  list(
    social=c("casino","teatro","espolón",
             "Paseo de Verano","Paseo de los curas",
             "calle","plaza","tertulia","salon"),
    religioso=c("catedral","capilla","sacristía",
                "claustro","seminario"),
    doméstico=c("vivero","\\bcasa\\b","hogar","alcoba",
                "habitación","cama","cocina","despensa")))

# Filtra las palabras clave empleando
# el nuevo diccionario
ft <- filterWords(cp, dicf)

# Añade la palabra capítulo al número
# de los capítulos para facilitar la
# lectura de los datos
ft$name <- paste0("Capítulo ",ft$name)

# Genera el gráfico de dispersión léxica
# circular interactivo
plotSpike(ft, 
          title = 'Los espacios de "La Regenta"', 
          subtitle = "Gráfico de dispersión léxica para distintos tipos de espacio.", 
          palette = pal$cat.brewer.Dark2.8[c(1:4)],
          label.size = 3, 
          line.width = 0.3, 
          ring.col="black")


Ahora, los patrones quedan mucho más evidentes. Los espacios religiosos se destacan en los dos primeros capítulos de forma clara, así como en el capítulo 23. Además, es ahí donde termina la novela. Los ambientes domésticos, predominantes en los pasajes dedicados a la interacción con Ana, que se alternan con los espacios “sociales” en los que se desenvuelve la vida de la ciudad y de los demás personajes.

Peso de los temas

¿Cuál la importancia de cada tema en la obra? Para responder a esta pregunta, podemos calcular la prevalencia de los temas en el texto. El peso de un tema se calcula de dos maneras:

  1. por la frecuencia absoluta - que consiste en solamente contar el número de palabras clave asociadas a ese tema en el texto; o

  2. por la frecuencia relativa - obtenida dividiendo el número de palabras clave asociadas a ese tema por el número total de palabras en el texto. En ese sentido, representa una medida de densidad del tema.

Mientras que la frecuencia absoluta nos da una idea de la cantidad de veces que un tema es mencionado, la frecuencia relativa nos permite comparar la importancia de los temas en textos de diferente longitud.

Code
# La función countKeywords
# cuenta las palabras clave de un
# diccionario en un texto
xy <- countKeywords(cp, 
                    dic, 
                    rel.freq = F, 
                    quietly = TRUE)

# Elimina los términos no encontrados
xy <- xy[xy$frequency>0,]

# Elimina la variable de grupos
# (no hay grupos en este caso)
xy$groups <- NULL

# Muestra los resultados
reactable(xy, resizable = TRUE)


Si ordenamos los valores de la frecuencia del mayor al menor, vemos que el misticismo y el adulterio aparecen entre los más frecuentes. El primero, por la presencia de Fermín de Pas y su relación con Ana, y el segundo, por la trama principal de la novela. El espacio de la casa también es relevante.

Sin embargo, la tabla no contiene información agregada por tema. Podríamos utilizar una función en R para agregar los resultados o emplear diferentes técnicas de visualización para comparar los temas. En este caso, utilizaremos un gráfico de redes jerárquicas para visualizar la relación entre los temas y su frecuencia en el texto.

Code
# Crea una red de temas con
# los resultados obtenidos
forceDirectedTree(xy,
                  value_col = "frequency",
                  max.radius = 60,
                  height=500)


Vemos círculos de distintos tamaños en el gráfico. Representan los grandes temas y su tamaño indica su peso en la novela. Cada uno posee un conjunto de otros círculos más pequeños de mismo color que indican la importancia de cada palabra clave dentro del tema. Así que el “Misticismo”, por ejemplo, aparece como el tema más relevante y “Magistral”, “Diós” y “Fermín” como sus palabras clave centrales. La economía, por otra parte, parece no importar mucho en Vetusta.

Otra manera de visualizar los mismos datos es a través de un treemap. En este caso, los temas se representan como rectángulos de distintos tamaños y colores, donde el tamaño indica la importancia del tema y el color, su relación con otros temas. El gráfico abajo es una versión modificada que emplea el algoritmo de Voronoi para distribuir las áreas de forma precisa, pero con formas más libres, incluso no rectangulares. Se llama Voronoi Tree.

Code
# Gráfico de Voronoi
plotVoronoiTree(data = xy,
                value_col = "frequency")


La diferencia central entre este último gráfico y el anterior se encuentra en el hecho de que la atención está centrada en la contribución de las palabras clave en la composición de cada tema. El la visualización anterior, el foco estaba en el peso relativo de los temas mucho más que en sus componentes empíricos concretos.

Personajes en lugar de temas

¿Qué tal si analizamos los personajes en lugar de los temas? ¿Cómo se distribuyen en la novela? ¿Cuál es su importancia relativa? Para responder a estas preguntas, podemos emplear la misma lógica de análisis de temas, pero aplicada a los personajes.

En primer lugar, creamos un diccionario con los personajes de la novela a partir de la nómina de personajes de la novela elaborada por Argüeles (1984).

Code
dich <- dictionary(
  list(
    hombres=
      list(
           Alvaro=c("Álvaro Mesía","Álvaro","Mesía",
                    "presidente del casino"),
           Saturnino=c("Saturnino Bermúdez","Saturnino",
                       "Bermúdez","Saturno","Saturnillo"),
           Fermin=c("Magistral","Provisor","Fermín",
                    "De Pas","Fermín de Pas","Magistral"),
           Victor=c("Víctor","Víctor Quintanar","Quintanar"),
           Otros=c(
                   "Agustinito","Amadeo","Anacleto",
                   "Anselmo","Antero","Antón Raíces",
                   "Antonio","Barcaza","Basilio",
                   "Bautista","Bedoya","Belisario",
                    "Benítez","Bismark","Campillo",
                   "\\b[C]hato\\b","don Carlos",
                   "Peláez","Cayetano",
                   "Cayetano Ripamilán","Ripamilán",
                   "Celedonio","Colás","marqués de Corujedo",
                   "Frígilis","Crespo","Custodio",
                   "Olías de Cuervo","señor Cuervo",
                   "Diego","Escosura","\\b[E]studiante\\b",
                   "Pepe","Trabuco","Foja","Fortunato",
                   "Francisco de Asís","Francisco de Pas",
                   "Francisco de Osuna","Francisco Páez", 
                   "señor Páez", "señor de Páez",
                   "Francisco Carraspique","Froilán",
                   "don Frutos","Frutos Redondo","Fulgosio",
                   "Germán","Glocester","Restituto",
                   "señor Infanzón", "el Infanzón",
                   "Iriarte","Joaquinito","Juanito",
                   "Leando","Maroto","marqués de Vegallana",
                   "\\s{1}[M]arqués\\b","Martínez",
                   "Matías","Matiella","monaguillo",
                   "señor Orgaz","\\b[P]alma\\b",
                   "Paco","Paquito","Palomo",
                   "Rodríguez","Parcerisa","Pedro",
                   "\\b[P]erales\\b","Pinón",
                   "Pompeyo","Pompeyo Guimarán","Guimarán",
                   "Robustiano","señor Roque",
                   "Rosendo","don Santos","Sousa",
                   "Trifón","\\b[V]inagre\\b",
                   "Vinculete")
           ),
    mujeres=
      list(
        Ana=c("Ana","Anita","Regenta"),
        Obdulia=c("Obdulia","Obdulia Fandiño",
                  "Fandiño","Obdulita"),
        Otras=c(
                "Agapita","Águeda","Angelina",
                "Anuncita","doña Anuncia","Camila",
                "Carolina","Señora de Infanzón", "la Infanzón",
                "Celestina","Edelmira","Emma",
                "Fabiolita","Fulgencia","Gertrudis",
                "la González","Juana","Lola",
                "doña Lucía","marquesa","Rufina",
                "Olvido","doña Paula","Pepa",
                "Guimarán, Perpétua","\\b[P]ilar\\b",
                "Petra","doña Petronila","Ramona",
                "\\bRita\\b","\\bRosa\\b","Rosita",
                "Rudesinda","Servanda","Társila",
                "\\b[T]eresa\\b","Teresina",
                "Úrsula","Visitación","\\b[V]isita\\b",
                "viuda del marqués de Corujedo")
        )
  )
)


Como se puede observar, se tratan de muchos personajes, algunos de ellos con varios nombres o formas de denominación. Una vez que ya tenemos el diccionario en manos, podemos proceder a contar la frecuencia de aparición de los personajes en la novela.

Para añadir emoción al asunto, vamos a hacerlo por capítulo. De esa manera, seremos capaces de acompañar la evolución de los personajes a lo largo de la novela, su participación en cada etapa y su rol en la estructura.

Code
# cuenta la frecuencia de los personajes
# en la novela por capítulo
xp <- countKeywords(cp, 
                    dich, 
                    rel.freq = F, 
                    group.var = "capitulo",
                    quietly = TRUE)

# Agrega los resultados por los dos niveles
# de código del diccionario
xx <- aggregate(list(frequency=xp$frequency), 
                by=list(groups=xp$groups, 
                        level1=xp$level2), 
                sum, na.rm=T)

# Elimina los términos no encontrados
# en el corpus
xx <- xx[xx$frequency>0,]

# Ordena por capítulo
xx <- xx[order(xx$groups),]

# Muestra los resultados
reactable(xx, resizable=TRUE)


Podemos ver cómo Ana ni siempre es la que más aparece asociada a otros en la novela. En algunos capítulos Fermín o Álvaro toman la delantera, mientras que en otros pasajes el protagonismo es más coral, con varios personajes siendo mencionados simultáneamente.

Como en el ejemplo anterior, también podemos emplear técnicas de visualización de datos para representar la información de manera más clara y atractiva. No obstante, ahora disponemos de una información adicional -el capítulo-, de modo que la información está más detallada y requiere otros enfoques para su representación gráfica.

Una primera alternativa consiste en emplear un diagrama de Sankey, que nos permitirá visualizar la relación entre los personajes y los capítulos. Se trata de un diagrama de flujo en el que los nodos representan las entidades y las conexiones entre ellos las relaciones. En este caso, los nodos serán los personajes y los capítulos, y las conexiones las apariciones de los personajes en los capítulos.

La función plotSankey de tenet nos permite hacerlo de manera sencilla. solo tenemos que indicarle los datos, el nodo de origen (“from=”), el nodo de destino (“to=”) y el valor (“value=”) que queremos representar.

Code
plotSankey(xx, 
           from = "level1", 
           to="groups", 
           value = "frequency", 
           opacity = 0.05)


Los resultados son reveladores. Aunque Ana es el personaje que más aparece en la novela, su presencia no es constante a lo largo de los capítulos. En algunos de ellos, como el 8 o el 22, aparece de modo tímido. Esta tendencia resulta aún más acentuada en el caso de los demás personajes.

Aunque el diagrama de Sankey es una buena opción, posee una limitación clara: solo permite visualizar los datos de un personaje o un capítulo a la vez. Para superar dicha restricción, podemos emplear un diagrama de flujo (streamgraph) que nos permita visualizar la evolución de todos los personajes a lo largo de los capítulos.

Lo haremos con la función plotStream de tenet. Al igual que en el caso anterior, solo tenemos que indicarle los datos, el nodo de origen (“x=”), el nodo de destino (“y=”) y el grupo (“group=”). También podemos elegir la paleta de colores que queremos emplear (“palette=”).

Code
plotStream(xx, 
           x="groups",
           y="frequency", 
           group="level1",
           palette=pal$cat.ggsci.simpsons.16)


En este último gráfico queda más clara la evolución de los personajes en la novela y los momentos en los que el autor decide vincularles más o menos en su narrativa. Además, al pasar el cursor sobre un capítulo, podemos ver la frecuencia de aparición de todos y cada uno de los personajes en ese capítulo en concreto.

Asociación entre temas (y personajes)

Hasta ahora hemos analizado la frecuencia de aparición de los personajes en la novela y cómo esta varía a lo largo de los capítulos. No obstante, también podemos estudiar la relación que los temas desarrollan entre sí. ¿Hasta qué punto dos ideas o conceptos aparecen en el mismo párrafo o capítulo del libro? Por ejemplo, ¿cuál es la relación entre iglesia y misticismo o entre sentimientos y el tiempo?

Para responder a estas preguntas, vamos a emplear la función matchCodes de tenet. Esta función nos permite calcular la frecuencia en la que dos códigos del mismo diccionario aparecen juntos en cada frase, párrafo, capítulo o otra unidad de agregación del corpus.

Code
# Reorganiza el corpus según
# sentencias o frases
cs <- corpus_reshape(cp, "sentences")

# Calcula la frecuencia en la
# que dos codigos del mismo 
# diccionario aparecen juntos
# en cada frase
d1 <- matchCodes(cs, 
                dic, 
                level = 1, 
                quietly=TRUE)

# Ordena los resultados de mayor a menor
d1 <- d1[order(d1$value, decreasing = T),]

# Muestra los resultados
plotChord(d1, 
          from = "term1", 
          to ="term2", 
          value= "value")


Como vemos, los conceptos se encuentran muy relacionados entre sí. No resulta nada sorprendente que haya una alta frecuencia de aparición de “misticismo” en las mismas frases en las que aparece “iglesia” o “religión”. De igual modo, la relación entre “sentimientos” y “tiempo” es muy estrecha, lo que sugiere que el autor emplea el tiempo como un recurso narrativo para expresar los sentimientos de los personajes. La sociedad, curiosamente, parece tener la misma predilección por el “misticismo” y el “adulterio”.

Esta estrategia se puede hacer más compleja si se emplean más categorías o si combinamos personajes y temas en un mismo diccionario. Cabe a cada uno determinar cuál es la perspectiva que resulta más fructífera para llevar a cabo el análisis. Las posibilidades son muy amplias y permiten una gran maleabilidad.

Podemos repetir el mismo análisis con los personajes. ¿Qué personajes se relacionan más entre sí? ¿Cuáles son los personajes que presentan más vínculos con los demás? ¿Existe algún tipo de liderazgo o influencia entre ellos? Volvemos a aplicar el mismo método, pero ahora con un diccionario de personajes más detallado, sin agregar en una categoría “otros y otras”.

El primer paso consiste en crear un diccionario con todos los personajes sin agregar.

Code
# diccionario de personajes
# sin agregar en una categoría
# otros y otras
dic.per <- dictionary(
  list(
    hombres=
      list(
        Alvaro=c("Álvaro Mesía",
                 "Álvaro",
                 "Mesía",
                 "presidente del casino"),
        Saturnino=c("Saturnino Bermúdez",
                    "Saturnino",
                    "Bermúdez",
                    "Saturno",
                    "Saturnillo"),
        Fermin=c("Magistral",
                 "Provisor",
                 "Fermín",
                 "De Pas",
                 "Fermín de Pas",
                 "Magistral"),
        Victor=c("Víctor",
                 "Víctor Quintanar",
                 "Quintanar"),
        Agustinito="Agustinito",
        Amadeo="Amadeo",
        Anacleto="Anacleto",
        Anselmo="Anselmo",
        Antero="Antero",
        Antón="Antón Raíces",
        Antonio="Antonio",
        Barcaza="Barcaza",
        Basilio="Basilio",
        Bautista="Bautista",
        Bedoya="Bedoya",
        Belisario="Belisario",
        Benítez="Benítez",
        Bismark="Bismark",
        Campillo=c("Campillo","\\b[C]hato\\b"),
        Carlos="Carlos",
        Pelaez="Peláez",
        Ripamilan=c("Cayetano",
                    "Cayetano Ripamilán",
                    "Ripamilán"),
        Celedonio="Celedonio",
        Colás="Colás",
        Corujedo="marqués de Corujedo",
        Frígilis=c("Frígilis","Crespo"),
        Custodio=c("Custodio"),
        Cuervo=c("Olías de Cuervo","señor Cuervo"),
        Diego="Diego",
        Escosura="Escosura",
        Estudiante=c("\\b[E]studiante\\b","Pepe","Trabuco"),
        Foja="Foja",
        Fortunato="Fortunato",
        "Francisco de Asís"="Francisco de Asís",
        "Francisco de Pas"="Francisco de Pas",
        "Francisco de Osuma"="Francisco de Osuna",
        Páez=c("Francisco Páez", "señor Páez", "señor de Páez"),
        "Francisco Carraspique"="Francisco Carraspique",
        Froilán="Froilán",
        Frutos=c("don Frutos","Frutos Redondo"),
        Fulgosio="Fulgosio",
        Germán="Germán",
        Glocester=c("Glocester","Restituto"),
        Infanzón=c("señor Infanzón", "el Infanzón"),
        Iriarte="Iriarte",
        Joaquinito="Joaquinito",
        Juanito="Juanito",
        Leandro="Leando",
        Maroto="Maroto",
        Vegallana=c("marqués de Vegallana","\\s{1}[M]arqués\\b"),
        Martínez="Martínez",
        Matías="Matías",
        Matiella="Matiella",
        monaguillo="monaguillo",
        "señor Orgaz"="señor Orgaz",
        Palma="\\b[P]alma\\b",
        Paquito=c("Paco","Paquito"),
        Palomo=c("Palomo","Rodríguez"),
        Parcerisa="Parcerisa",
        Pedro="Pedro",
        Perales="\\b[P]erales\\b",
        Pinón="Pinón",
        Pompeyo=c("Pompeyo","Pompeyo Guimarán","Guimarán"),
        Robustiano="Robustiano",
        Roque="señor Roque",
        Rosendo="Rosendo",
        Santos="don Santos",
        Sousa="Sousa",
        Trifón="Trifón",
        Vinagre="\\b[V]inagre\\b",
        Vinculete="Vinculete"
        ),
    mujeres=
      list(
        Ana=c("Ana",
              "Anita",
              "Regenta"),
        Obdulia=c("Obdulia",
                  "Obdulia Fandiño",
                  "Fandiño",
                  "Obdulita"),
        Agapita="Agapita",
        Águeda="Águeda",
        Angelina="Angelina",
        Anunciación=c("Anuncita","doña Anuncia"),
        Camila="Camila",
        Carolina=c("Carolina","Señora de Infanzón", "la Infanzón"),
        Celestina="Celestina",
        Edelmira="Edelmira",
        Emma="Emma",
        Fabiolita="Fabiolita",
        Fulgencia="Fulgencia",
        Gertrudis="Gertrudis",
        "La González"="la González",
        Juana="Juana",
        Lola="Lola",
        Lucía="doña Lucía",
        Marquesa=c("marquesa","Rufina"),
        Olvido="Olvido",
        Paula="doña Paula",
        Pepa="Pepa",
        Perpétua="Guimarán, Perpétua",
        Pilar="\\b[P]ilar\\b",
        Petra="Petra",
        Petrolina="doña Petronila",
        Ramona="Ramona",
        Rita="\\bRita\\b",
        Rosa="\\bRosa\\b",
        Rosita="Rosita",
        Rudesinda="Rudesinda",
        Servanda="Servanda",
        Társila="Társila",
        Teresa="\\b[T]eresa\\b",
        Teresina="Teresina",
        Úrsula="Úrsula",
        Visita=c("Visitación","\\b[V]isita\\b"),
        "Viuda de Corujedo"="viuda del marqués de Corujedo"
        )
  )
)


Una vez que se ha definido el diccionario, se procede a cargar el corpus y a calcular las asociaciones entre los códigos del diccionario. Para ello, se emplea la función matchCodes() del paquete tenet. Esta función calcula la frecuencia en la que dos códigos del mismo diccionario aparecen juntos en cada párrafo.

Para facilitar el análisis de asociaciones entre personajes, hemos decidido eliminar las asociaciones con el código Ana. Resulta obvio que La Regenta es el personaje principal de la novela y, por tanto, aparecerá en la mayoría de los párrafos. Al eliminar esta constante, nuevos patrones emergen y posibilitan enriquecer el análisis. A continuación, se presenta el código que permite realizar este cálculo:

Code
# Emplea el corpus organizado
# según párrafos
cpp <- corpus(regp, 
              text_field = "texto")

# Calcula la frecuencia en la
# que dos códigos del mismo 
# diccionario aparecen juntos
# en cada párrafo
d1 <- matchCodes(cpp, 
                 dic.per, 
                 level = 2, 
                 quietly=TRUE)

# Ordena los resultados de mayor a menor
d1 <- d1[order(d1$value, decreasing = T),]

# Elimina las asociaciones con Ana
d1 <- d1[d1$term1!="Ana",]
d1 <- d1[d1$term2!="Ana",]

# Genera un gráfico de cuerdas
# para visualizar las asociaciones
plotChord(d1, 
          from = "term1", 
          to ="term2", 
          value= "value", 
          elementId = "chord3")


El gráfico de cuerdas muestra la centralidad de Fermín y Álvaro, que presentan vínculos con un abanico amplio de personajes. Los demás, se enmarcan en relaciones más específicas y limitadas. Petra, por ejemplo, actúa como intermediaria entre Ana y sus admiradores y esta “función” queda patente en sus conexiones con Fermín, Álvaro y Víctor (que en ese caso es su patrón).

Además, la importancia de los personajes puede variar según cada capítulo. Por ejemplo, en el capítulo 4, donde se describe la infancia de Ana, aparecen personajes como Camila, Carlos y Germán, que, luego, apenas vuelven a ser mencionados. Por eso, sería interesante analizar cómo la red de asociación entre personajes varía según el capítulo.

El siguiente código genera una visualización de red para cada capítulo que muestra la frecuencia en que los personajes aparecen juntos en los mismos párrafos. Hemos elegido eliminar a Ana por dos motivos. Primero, para facilitar la visualización, puesto que se trata del personaje principal y que aparece relacionada a casi todos los demás. Segundo, y más importante, su ausencia nos permite observar las relaciones entre los demás personajes, que de otro modo quedarían opacadas por la presencia de Ana. Por ejemplo, de ese modo podemos ver mejor cuándo Fermín y Álvaro toman el centro de la narración o cuando otros personajes interesantes, como la marquesa, se destacan.

Code
# Carga los paquetes necesarios
library(network)
library(sna)
library(ggnetwork)
library(ggplot2)

# Crea una lista para guardar
# los gráficos de red
# de cada capítulo
px <- list()

# Para cada capítulo
for(i in 1:30){

  # Extrae el texto del capítulo
  c1 <- cp[i]
  
  # Reorganiza en párrafos
  c1 <- corpus_reshape(c1, to="paragraphs")
  
  # Calcula la frecuencia de los
  # personajes
  d1 <- matchCodes(c1, 
                   dic.per, 
                   level = 2, 
                   quietly=TRUE)
  
  # Elimina a Ana para facilitar
  # la visualización
  d1 <- d1[d1$term1!="Ana",]
  d1 <- d1[d1$term2!="Ana",]

  # Ordena los resultados
  d1 <- d1[order(d1$value, decreasing = T),]

  # Crea una red
  n1 <- network(d1, 
                directed = F)
  
  # Convierte en un layout
  # de red para la visualización
  gn <- ggnetwork(n1, 
                  layout = "kamadakawai", 
                  cell.jitter = 0.75)

  # Genera el gráfico
  p <- ggplot(gn, 
              aes(x = x, 
                  y = y, 
                  xend = xend, 
                  yend = yend)) +
          geom_edges(
                color = "grey90",
                aes(size=value), 
                curvature=0.25) +
        geom_edges(
                size=0.1, 
                curvature=0.25, 
                color="purple") +
          geom_nodetext(
                aes(label = vertex.names),
                fontface = "bold")+
          theme_blank()+
          labs(title=paste0("**Capítulo ",i,"**"))+
          theme(plot.title = 
                  ggtext::element_markdown(
                          size=15, 
                          color="darkgreen"), 
                legend.position = "none",
                plot.margin=grid::unit(
                  c(0.75,0.75,0.75,0.75), 
                  "cm"))

  # Almacena el gráfico en
  # la lista
  px[[i]] <- p

}

# Carga el paquete que
# permitirá visualizar
# las 30 redes en un
# solo gráfico
library(egg)

# Organiza los gráficos
# en tres columnas y diez
# filas
ggarrange(plots=px, 
          ncol=3, 
          nrow=10)

La figura nos muestra que cada capítulo presenta un patrón distinto de interacción entre los personajes. La complejidad de las redes también varía de modo considerable. En algunos casos, como los capítulos 4 y 7, la red es muy simple, con pocos personajes y pocas conexiones. En otros, como el capítulo 13, la red es mucho más densa y compleja. En general, Fermín y Álvaro son los personajes más centrales, pero no siempre. En algunos capítulos, otros personajes, como la marquesa, toman el centro de la narración.

Clusters y escalonado de textos

Análisis de conglomerados (clusters)

El análisis de conglomerados es una técnica que permite agrupar textos en función de su similitud. En el ejemplo abajo, se utiliza un algoritmo de agrupamiento jerárquico para agrupar los capítulos de la novela en función de la similitud de sus palabras. La similitud se mide a partir de la distancia euclidiana entre ellos.

Code
# Crea los tokens
tk <- tokens(cp, 
             remove_punct = T, 
             remove_numbers = T, 
             remove_separators = T, 
             remove_symbols = T)

# Remueve las palabras vacías
tk <- tokens_remove(tk, 
                    pattern=stopwords("es"))

# Crea la matriz de frecuencias
dtm <- dfm(tk)

# Carga el paquete necesario
library(quanteda.textstats)

# Calcula la distancia entre 
# los capítulos y los agrupa en
# conglomerados
tstat_dist <- as.dist(textstat_dist(dtm))
clust <- hclust(tstat_dist)

# Muestra los resultados
plot(clust, xlab = "Distance", ylab = NULL)


El dendrograma representa una forma de representación visual de las distancias entre los capítulos. Vemos existe un gran grupo de capítulos (con sus subgrupos) y dos conglomerados más pequeños. Uno, formado por los capítulos 12, 13, 16, 20, 21 y 22 y, otro, por el 29 y 30.

Como podemos ver, la organización en grupos resulta coherente con el desarrollo temático de cada parte de la novela. Por ejemplo, los capítulos 4 y 5 cuentan la infancia y juventud de Ana. El 29 y el 30 son los que concluyen la obra con la consumación del adulterio y su desenlace trágico.

Los apartados 12, 20 y 22, por otro lado, se centran en la relación de Fermín con sus detractores y en la muerte de Don Santos. Los capítulos 13, 16 y 21, por otro lado, se centran en las tentaciones iniciales de Ana con Mesía y en su entrega al misticismo intermediada por Fermín.

El 11 y el 15 se dedican a la relación de Fermín con su madre.

Los capítulos 1, 2, 3, 6, 7, 8,14 y 24, por otro lado, describen la presentación de los personajes principales, vida social de Vetusta, el carácter de Fermín, así como las fiestas en el casino y en casa de los marqueses.

Finalmente, el bloque representado por los apartados 9, 10, 17, 18, 19, 23, 25, 26, 27 y 28 se centra en los constantes titubeos de Ana entre el misticismo (representado por Fermín) y el romanticismo / erotismo (simbolizado por Mesía).

Escalonado unidimensional de textos: Wordfish

El escalonado de textos es una técnica que permite visualizar la relación entre textos en un espacio unidimensional. La técnica empleada en este caso es el Wordfish (Slapin and Proksch 2008). Se trata de una técnica de estimación de puntos ideales a partir de modelos estadísticos que parten de las frecuencias de las palabras. En este caso, hemos aplicado el escalonado de textos a los capítulos de La Regenta para ver cómo se relacionan entre sí.

Code
library(quanteda.textmodels)
library(quanteda.textplots)
library(ggplot2)

wf <- textmodel_wordfish(dtm)

textplot_scale1d(wf) +
  geom_hline(yintercept = 0, 
             linetype = "dashed",
             color="red3")

Esta escala se podría interpretar de distintas maneras. Una de ellas es que los capítulos situados más a la izquierda representan una mayor intensidad de la vida social de Vetusta, mientras que aquellos más a la derecha se relacionan con la vida privada, íntima y la infancia de La Regenta.

También podríamos leer los resultados de acuerdo con el protagonismo o mayor centralidad de ciertos personajes según el punto de la escala. Más a la izquierda predominan los Marqueses, Álvaro Mesía (antes de su relación con Ana Ozores) y la sociedad vetustense. En el centro se sitúa Fermín de Pas, que se interpone entre la vida privada de Ana y la vida en sociedad. En la derecha encontramos a Víctor, su esposo, Álvaro (hechos consumados) y en el extremo, la familia de Ana, especialmente en su infancia.

De todas formas, ambas interpretaciones sugieren una dualidad entre la vida íntima y relativamente reservada de Ana en contraste con la vida social y pública de Vetusta. Los dos mundos se tocan en ocasiones concretas por intermedio de algunos actores que transitan dentre ellos, como Fermín de Pas o Álvaro Mesía.

Análisis de correspondencia (CA)

El análisis de correspondencia es una técnica de reducción de dimensionalidad de bases de datos complejas. En nuestro caso, tenemos una matriz de frecuencia de palabras en la que cada palabra representa una dimensión. El análisis de correspondencia permite reducir el número de dimensiones para que permitan visualizar la relación entre los textos. El objetivo consiste en situar a los capítulos en un espacio bidimensional que permita revelar características estructurales latentes en la obra.

Code
# Carga los paquetes
library(quanteda.textmodels)
library(ggplot2)
library(ggrepel)

# Ejecuta el análisis de correspondencias
cca <- textmodel_ca(dtm)

# Extrae las coordenadas de los capítulos
dd <- data.frame(cca$rowcoord)
dd$name <- as.character(rownames(dd))
dd <- dd[, c("name", "Dim1", "Dim2")]

# crea un gráfico de dispersión 
# para examinar los resultados
ggplot(dd, aes(x = Dim1, y = Dim2)) +
  geom_point() +
  geom_text_repel(aes(label = name)) +
  theme_classic() +
  theme(legend.position = "none")+
  geom_hline(yintercept = 0, 
             color = "red3", 
             linetype = "dashed") +
  geom_vline(xintercept = 0, 
             color = "red3", 
             linetype = "dashed")+
  xlab("Dimensión 1") +
  ylab("Dimensión 2") +
  labs(title = "Análisis de correspondencias")

El gráfico de dispersión muestra la relación entre los capítulos de La Regenta en un espacio bidimensional. Los capítulos se sitúan en función de su relación semántica. Los capítulos más cercanos entre sí comparten un mayor número de palabras y, por tanto, una mayor relación semántica. Los capítulos más alejados, por otro lado, comparten menos palabras y, por tanto, una menor relación semántica.

La distancia al punto de origen (0,0) indica el peso del capítulo en cada una de las dimensiones. Por ejemplo, el capítulo 1 tiene un importante peso en ambos ejes, así como el 06. No obstante, el 22 y el 05 se destacan en la segunda dimensión, pero con poca incidencia sobre la primera.

En los resultados, llama la atención el conglomerado de capítulos que se concentran en la parte derecha del gráfico. En su mayoría, se ubican en la segunda parte de la novela, donde se narra la evolución de la relación entre Ana y Mesía, así como el desenlace trágico de la obra. Por otro lado, los capítulos periféricos se relacionan con la vida social de Vetusta, los desarrollos específicos de Fermín y la presentación de los personajes.

References

Benito Argüelles, Juan. 1984. “Nómina de Personajes de "La Regenta".” Los Cuadernos Del Norte: Revista Cultural de La Caja de Ahorros de Asturias 5 (23): 10–18.
Slapin, Jonathan B., and Sven-Oliver Proksch. 2008. “A Scaling Model for Estimating Time-Series Party Positions from Texts.” American Journal of Political Science 52 (3): 705–22. https://doi.org/10.1111/j.1540-5907.2008.00338.x.

Footnotes

  1. No nos detendremos aquí en explicar los detalles del cálculo de los indicadores. Cada técnica suele estar asociada a un artículo o referencia de ayuda que aclara el algoritmo. Para saber más sobre la función textstat_collocations, puedes consultar la ayuda en R ejecutando el comando help(textstat_collocations) de la consola de R.↩︎